package com.joey.cloud.communal.utils;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.joey.cloud.communal.constant.BaseConstant;
import com.joey.cloud.communal.dto.UserAuthDto;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.Set;

/**
 * jwt权限工具类
 * @author joey
 */
//@Component
public class JwtUtils {
    public static String claimKey="data";
    public static String secret="joe123456";
    public static String headerToken="JoeToken";
    public static Long expiration=3600000L;
    public static Long refresh=3600000L;

    /**
     * 获取traceId
     * @return
     */
    public static Long getTraceId(){
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        Long traceId = (Long)request.getAttribute(BaseConstant.TRACT_ID);
        return traceId;
    }

    /**
     * 获取当前用户id
     * @return
     */
    public static Long getCurrentUserId(){
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        Object psnId = request.getAttribute("psnId");
        if(psnId==null){
            String token = JwtUtils.getTokenByHeader();
            if(StrUtil.isNotEmpty(token)){
                String psnIdStr = JwtUtils.getId(token);
                if(StrUtil.isNotEmpty(psnIdStr)){
                    request.setAttribute("psnId", psnIdStr);
                    return Long.parseLong(psnIdStr);
                }
            }
            return null;
        }
        return Long.parseLong(psnId.toString());
    }
    /**
     * 获取当前用户id
     * @return
     */
    public static Long getCurrentUserIdNoException(){
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        Object psnId = request.getAttribute("psnId");
        if(psnId==null){
            String token = JwtUtils.getTokenByHeader();
            if(StrUtil.isNotEmpty(token)){
                try {
                    String psnIdStr = JwtUtils.getId(token);
                    if(StrUtil.isNotEmpty(psnIdStr)){
                        request.setAttribute("psnId", psnIdStr);
                        return Long.parseLong(psnIdStr);
                    }
                }catch (Exception e){
                    return null;
                }
            }
            return null;
        }
        return Long.parseLong(psnId.toString());
    }
    /**
     * 获取当前token
     * @return
     */
    public static String getTokenByHeader(){
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String token = request.getHeader(headerToken);
        return token;
    }

    /**
     * 根据当前token刷新token
     * @return
     */
    public static String refreshToken(){
        try {
            String token = getTokenByHeader();
            if(StrUtil.isEmpty(token)){
                return null;
            }
            boolean expiration = JwtUtils.isExpiration(token);
            if(!expiration){
                return token;
            }
        }catch (ExpiredJwtException e){
            Date expirationDate = e.getClaims().getExpiration();
            Date date = new Date(System.currentTimeMillis() - refresh);
            //如果在token刷新时间以内则返回刷新token
            if(date.before(expirationDate)){
                Object obj = e.getClaims().get(JwtUtils.claimKey);
                String psnId = e.getClaims().getId();
                return JwtUtils.generateToken(psnId, obj);
            }
        }catch (Exception e){
            throw new RuntimeException("刷新token出错",e);
        }
        return null;
    }
    /**
     * 生成token
     * @param psnId
     * @param dto
     * @return
     */
    public static String generateToken(String psnId, Object dto) {
        return Jwts.builder()
                .signWith(SignatureAlgorithm.HS512, secret)
                .setId(psnId)
                .setSubject("joey")
                .claim(claimKey,dto)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + expiration))
                .compact();
    }

    /**
     * 生成token
     * @param psnId
     * @param groupKeyList
     * @param roleKeyList
     * @return
     */
    public static String generateToken(Long psnId, Set<String> groupKeyList, Set<String> roleKeyList) {
        UserAuthDto dto = new UserAuthDto();
        dto.setPsnId(psnId);
        dto.setGroupList(groupKeyList);
        dto.setRoleList(roleKeyList);
        return Jwts.builder()
                .signWith(SignatureAlgorithm.HS512, secret)
                .setId(psnId.toString())
                .setSubject("joey")
                .claim(claimKey,dto)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + expiration))
                .compact();
    }

    public static String generateToken(Long psnId) {
        return Jwts.builder()
                .signWith(SignatureAlgorithm.HS512, secret)
                .setId(psnId.toString())
                .setSubject("joey")
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + expiration))
                .compact();
    }

    /**
     * 从token中获取id
     * @param token
     * @return
     */
    public static String getId(String token){
        return getTokenBody(token).getId();
    }

    /**
     * 是否已过期
     * @param token
     * @return
     */
    public static boolean isExpiration(String token){
        return getTokenBody(token).getExpiration().before(new Date());
    }

    /**
     * 获取用户权限信息
     * @return
     */
    public static UserAuthDto getUserInfo(String token){
        if(token==null){
            return null;
        }
        Claims c = getTokenBody(token);
        String json = JSONObject.toJSONString(c.get(claimKey));
        UserAuthDto dto = JSONObject.parseObject(json, UserAuthDto.class);
        return dto;
    }

    private static Claims getTokenBody(String token){
        return Jwts.parser()
                .setSigningKey(secret)
                .parseClaimsJws(token)
                .getBody();
    }


    @Value("${jwt.claimKey}")
    public void setClaimKey(String claimKey) {
        JwtUtils.claimKey = claimKey;
    }
    @Value("${jwt.headerToken}")
    public void setHeaderToken(String headerToken) {
        JwtUtils.headerToken = headerToken;
    }
    @Value("${jwt.secret}")
    public void setSecret(String secret) {
        JwtUtils.secret = secret;
    }
    @Value("${jwt.expiration}")
    public void setExpiration(Long expiration) {
        JwtUtils.expiration = expiration;
    }
    @Value("${jwt.refresh}")
    public void setRefresh(Long refresh) {
        JwtUtils.refresh = refresh;
    }
}
